#ifndef h_baseH
#define h_baseH

namespace h_base
{

class alloc
{
public :
   static void *allocate(size_t size)
   {
      return malloc(size);
   }
   static void deallocate(void *buf, size_t size)
   {
      free(buf);
   }
   static void *reallocate(void *buf, size_t old_size, size_t new_size)
   {
      if ( new_size <= old_size )
         return buf;
      void *new_buf = allocate(new_size);
      memcpy(new_buf, buf, old_size);
      deallocate(buf, old_size);
      return new_buf;
   }
};

//#define H_STRING
#ifdef H_STRING

class HString
{
public:

  enum { npos = (size_t)-1 };
  
  HString() : external_buf(0), external_buf_size(0), len(0)
  {
    internal_buf[0] = 0;
  }
  HString(char c)
  {
    len = 1;
    external_buf_size = 0;
    external_buf = 0;
    internal_buf[0] = c;
    internal_buf[1] = 0;
  }
  HString(const char* str)
  {
    len = strlen(str);
    if ( len > __INTERNAL_BUF_SIZE ) {
      external_buf_size = len + 1;
      external_buf = (char*)alloc::allocate(external_buf_size);
      strcpy(external_buf, str);
    } else {
      external_buf_size = 0;
      external_buf = 0;
      strcpy(internal_buf, str);
    }
  }
  HString(const void* buf, size_t buf_len)
  {
    len = buf_len;
    if ( len > __INTERNAL_BUF_SIZE ) {
      external_buf_size = len + 1;
      external_buf = (char*)alloc::allocate(external_buf_size);
      memcpy(external_buf, buf, len);
      external_buf[len] = 0;
    } else {
      external_buf_size = 0;
      external_buf = 0;
      memcpy(internal_buf, buf, len);
      internal_buf[len] = 0;
    }
  }
  HString(char c, size_t n)
  {
    len = n;
    if ( len > __INTERNAL_BUF_SIZE ) {
      external_buf_size = len + 1;
      external_buf = (char*)alloc::allocate(external_buf_size);
      memset(external_buf, c, len);
      external_buf[len] = 0;
    } else {
      external_buf_size = 0;
      external_buf = 0;
      memset(internal_buf, c, len);
      internal_buf[len] = 0;
    }
  }
  HString(const HString& obj)
  {
    len = obj.len;
    if ( len > __INTERNAL_BUF_SIZE ) {
      external_buf_size = len + 1;
      external_buf = (char*)alloc::allocate(external_buf_size);
      strcpy(external_buf, obj.c_str());
    } else {
      external_buf_size = 0;
      external_buf = 0;
      strcpy(internal_buf, obj.c_str());
    }
  }
  ~HString()
  {
    if ( external_buf != 0 )
    {
       alloc::deallocate(external_buf, external_buf_size);
    }
  }
  HString& operator=(const HString& obj)
  {
    if ( &obj == this )
      return *this;
    if ( external_buf != 0 )
      alloc::deallocate(external_buf, external_buf_size);
    len = obj.len;
    if ( len > __INTERNAL_BUF_SIZE ) {
      external_buf_size = len + 1;
      external_buf = (char*)alloc::allocate(external_buf_size);
      strcpy(external_buf, obj.c_str());
    } else {
      external_buf_size = 0;
      external_buf = 0;
      strcpy(internal_buf, obj.c_str());
    }
    return *this;
  }
  size_t length() const { return len; }
  const char *c_str() const
  {
    return external_buf == 0 ? internal_buf : external_buf;
  }
  void resize(size_t new_size)
  {
    if ( new_size == len )
      return;
    char *buf = external_buf == 0 ? internal_buf : external_buf;
    if ( new_size < len )
    {
      len = new_size;
      buf[len] = 0;
    } else {
      if ( external_buf == 0 ) {
        if ( new_size > __INTERNAL_BUF_SIZE ) {
          external_buf_size = new_size + 1;
          external_buf = (char*)alloc::allocate(external_buf_size);
          memcpy(external_buf, internal_buf, len);
          len = new_size;
          external_buf[len] = 0;
        } else {
          len = new_size;
          internal_buf[len] = 0;
        }
      } else {
        if ( new_size + 1 > external_buf_size ) {
          external_buf = (char*)alloc::reallocate(external_buf,
            external_buf_size, new_size + 1);
          external_buf_size = new_size + 1;
          len = new_size;
          external_buf[len] = 0;
        } else {
          len = new_size;
          external_buf[len] = 0;
        }
      }
    }
  }
  char& operator[](size_t index)
  {
    char *buf = external_buf == 0 ? internal_buf : external_buf;
    return buf[index];
  }
  const char& operator[](size_t index) const
  {
    const char *buf = external_buf == 0 ?
      internal_buf : external_buf;
    return buf[index];
  }
  HString& operator+=(const HString& obj)
  {
    size_t old_len = len;
    size_t str_len = obj.len;
    resize(len + str_len);
    char *buf = external_buf == 0 ? internal_buf : external_buf;
    memcpy(buf + old_len, obj.c_str(), str_len);
    return *this;
  }
  HString substr(size_t position, size_t sub_len = npos) const
  {
    if ( position >= len )
      position = len;
    if ( sub_len == npos )
      sub_len = len - position;
    return HString(c_str() + position, sub_len);
  }
  size_t find(char c, size_t position) const
  {
    const char *buf = external_buf == 0 ? internal_buf : external_buf;
    if ( position >= len )
      position = len;
    const char *s = strchr(buf + position, c);
    if ( s == NULL )
      return npos;
    else
      return s - buf;
  }
  size_t rfind(char c) const
  {
    const char *buf = external_buf == 0 ? internal_buf : external_buf;
    const char *s = strrchr(buf, c);
    if ( s == NULL )
      return npos;
    else
      return s - buf;
  }
  size_t find_last_not_of(char c) const
  {
    const char *buf = external_buf == 0 ? internal_buf : external_buf;
    const char *s = buf + len - 1;
    for ( ; s >= buf && *s == c; s-- )
       ;
    if ( s < buf )
      return npos;
    else
      return s - buf;
  }
protected:
  enum { __INTERNAL_BUF_SIZE = 64 };
  char internal_buf[__INTERNAL_BUF_SIZE + 1];
  char* external_buf;
  size_t external_buf_size;
  size_t len;
};

HString operator+(const HString& lhs, const HString& rhs);
bool operator==(const HString& lhs, const HString& rhs);
bool operator!=(const HString& lhs, const HString& rhs);
bool operator>(const HString& lhs, const HString& rhs);
bool operator>=(const HString& lhs, const HString& rhs);
bool operator<(const HString& lhs, const HString& rhs);
bool operator<=(const HString& lhs, const HString& rhs);

#else
   typedef string HString;
#endif

template<typename T>class HVector
{
public :
  typedef T* iterator;
  typedef const T* const_iterator;

   HVector<T>()
      : FUsedQty(0)
   {
   }
   void clear()
   {
      FUsedQty = 0;
   }
   void push_back(const T &Value)
   {
      if ( FUsedQty < FVec.size() )
      {
         FVec[FUsedQty] = Value;
      }
      else
      {
         FVec.push_back(Value);
      }
      FUsedQty++;
   }
   T &operator[](int Idx)
   {
      return FVec[Idx];
   }
   const T &operator[](int Idx) const
   {
      return FVec[Idx];
   }
   int size() const
   {
      return FUsedQty;
   }
   bool empty() const
   {
      return FUsedQty == 0;
   }
   iterator begin()
   {
      return &*FVec.begin();
   }
   const_iterator begin() const
   {
      return &*FVec.begin();
   }
   iterator end()
   {
      return &*(FVec.begin() + FUsedQty);
   }
   const_iterator end() const
   {
      return &*(FVec.begin() + FUsedQty);
   }
private :
   int FUsedQty;
   vector<T> FVec;
};

template<typename T>class HHashArray
{
public :
   struct HNode
   {
      HString Key;
      T Value;
      bool Used;
      int Prev;
      int Next;
      HNode()
         : Value(), Used(false), Prev(-1), Next(-1)
      {}
   };
   void Init(int Size)
   {
      FSize = Size;
      FEmptyQty = Size / 5;
      FTotalQty = FSize + FEmptyQty;
      Clear();
   }
   void Clear()
   {
      FVec.clear();
      FVec.resize(FTotalQty);
      for ( int i = 0; i < FEmptyQty - 1; i++ )
      {
         FVec[FSize + i].Next = FSize + i + 1;
      }
      FVec[FSize + FEmptyQty - 1].Next = -1;
      FEmptyHeader = FSize;
   }
   T &operator[](const HString &Key);
   T &operator[](int Idx);
   int Find(const HString &Key) const;
   int Size() const
   {
      return FVec.size();
   }
   void Erase(int Idx);
   int First() const;
   int Next(int Idx) const;
   int CalcHash(const HString &Key) const;
private :

   int FSize;
   int FEmptyQty;
   int FTotalQty;
   int FEmptyHeader;
   vector<HNode> FVec;
};

template<typename T>T &HHashArray<T>::operator[](const HString &Key)
{
   int Idx = CalcHash(Key);
   HNode *Node = &FVec[Idx];

   if ( !Node->Used )
   {
      *Node = HNode();
      Node->Key = Key;
      Node->Used = true;
      return Node->Value;
   }

   for ( ; ; )
   {
      if ( Node->Key == Key )
      {
         return Node->Value;
      }
      if ( Node->Next == -1 )
      {
         if ( FEmptyHeader == -1 )
         {
            fprintf(stderr, "[FATAL]Line %d, no space in hash array\n", __LINE__);
            exit(12);
         }
         int NewIdx = FEmptyHeader;
         HNode *NewNode = &FVec[NewIdx];
         FEmptyHeader = NewNode->Next;
         *NewNode = HNode();
         Node->Next = NewIdx;
         NewNode->Key = Key;
         NewNode->Used = true;
         NewNode->Prev = Idx;
         return NewNode->Value;
      }
      Idx = Node->Next;
      Node = &FVec[Idx];
   }
}

template<typename T>T &HHashArray<T>::operator[](int Idx)
{
   return FVec[Idx].Value;
}

template<typename T>int HHashArray<T>::Find(const HString &Key) const
{
   int Idx = CalcHash(Key);
   const HNode *Node = &FVec[Idx];

   if ( !Node->Used )
   {
      return -1;
   }

   for ( ; ; )
   {
      if ( Node->Key == Key )
      {
         return Idx;
      }
      if ( Node->Next == -1 )
      {
         return -1;
      }
      Idx = Node->Next;
      Node = &FVec[Idx];
   }
}

template<typename T>int HHashArray<T>::CalcHash(const HString &Key) const
{
   unsigned int Result = 0;
   const unsigned char *s = (const unsigned char*)Key.c_str();

   for ( ; *s != '\0'; s++ )
   {
      Result = Result * 23 + *s + 1;
   }

   return Result % Size();
}

template<typename T>void HHashArray<T>::Erase(int Idx)
{
   HNode *Node = &FVec[Idx];

   Node->Used = false;

   if ( Node->Prev == -1 )
   {
      if ( Node->Next != -1 )
      {
         int NextIdx = Node->Next;
         HNode *NextNode = &FVec[NextIdx];
         *Node = *NextNode;
         NextNode->Used = false;
         NextNode->Next = FEmptyHeader;
         FEmptyHeader = NextIdx;
      }
   }
   else
   {
      int PrevIdx = Node->Prev;
      HNode *PrevNode = &FVec[PrevIdx];
      PrevNode->Next = Node->Next;
      Node->Used = false;
      Node->Next = FEmptyHeader;
      FEmptyHeader = Idx;
   }
}

template<typename T>int HHashArray<T>::First() const
{
   int Idx = 0;

   for ( ; Idx < FTotalQty && !FVec[Idx].Used; Idx++ )
      ;

   if ( Idx == FTotalQty )
   {
      return -1;
   }
   else
   {
      return Idx;
   }
}

template<typename T>int HHashArray<T>::Next(int Idx) const
{
   Idx++;

   for ( ; Idx < FTotalQty && !FVec[Idx].Used; Idx++ )
      ;

   if ( Idx == FTotalQty )
   {
      return -1;
   }
   else
   {
      return Idx;
   }
}

// 对字符串中的环境变量进行求值
   HString EnvEvaluate(const HString &Str, map<HString, HString> *EnvMap = NULL);

// 判断一个字符是否在一个字符串内
   bool CharInStr(char c, const char *Str);

// 从文件f中读入一行到s，到文件尾返回-1，否则返回s的长度
// 如果一行超过MaxLen，则截取前面MaxLen个字符返回，后面的丢弃
// 行中如果有'\t'或者'\0'则替换成空格
// 填写到s的内容不包含最后的换行符
   int ReadLine(FILE *f, char *s, int MaxLen);
   int ReadLine(FILE *f, char *s, int MaxLen, bool TabToSpace);

// 从字符串s中获得子串，如果separators含有空格则忽略开头空格，返回
// 子串的下一个字符的位置
   int ReadWord(const char *s, char *w, const char *separators, int MaxLen);

// 将字符串s按照分隔符Delimiter拆成字符串数组
   void SplitString(const HString &s, char Delimiter,
      vector<HString> &Text, bool TrimSpace = false);

// SplitString的逆操作
   HString JoinStrings(const vector<HString> &Vec, char Delimiter);

// 将路径分解为目录、文件和后缀
   void SplitPath(const HString &Path, HString &DirName, HString &BaseName,
      HString &Postfix);

// 将 IP:PORT 格式地址分解
   void SplitIpPort(const HString &IpPort, HString &Ip, int &Port);

// 去除字符串尾部空格
   void RightTrim(HString &Str);

// 转换成大写
   void ToUpper(HString &Str);

// 转换成小写
   void ToLower(HString &Str);

// 转换成大写
   void ToUpper(char *s);

// 转换成小写
   void ToLower(char *s);

// 压缩文本文件
   bool TextFileCompress(const HString &SrcFileName,
      const HString &DesFileName, int &ErrCode);

// 解压缩文本文件
   bool TextFileDecompress(const HString &SrcFileName,
      const HString &DesFileName, int &ErrCode);

// 计算hash值
   unsigned int Hash(const void *Buf, int Len);

// 字符串转换成数值
   int StrToInt(const char *Str);
   long StrToLong(const char *Str);
   int HexStrToInt(const char *Str);
   float StrToFloat(const char *Str);
   double StrToDouble(const char *Str);
   long double StrToLongDouble(const char *Str);

// 时间（相对标准时间GMT 1970/1/1 秒）与时间字符串转换
   HString IntToString(int n);
   HString TimeToString(time_t Time);
   time_t StringToTime(const char *TimeStr);
   time_t StringToTime(const HString &TimeStr);
   HString CurrentDateTime();

// 获得本机IP地址
   void GetIpAddrVec(vector<HString> &AddrVec);

// 检查日期

   bool CheckDate(const char *DateStr);

class HRaw
{
public :

// 方法                功能
//-----------------------------------------------------------------------------
// 构造函数            可以指定预先分配的内存大小以及当内存不够时候自动分配的
//                     内存的单位大小
// size                获得数据的长度
// resize              改变数据长度
// clear               清空数据
// push_back           在数据尾追加一段新数据
// operator[]          取得第 n 个字符的引用
// data                返回数据的开始地址，数据结束处有'\0'
// sub_string          将指定位置开始（偏移量从 0 开始计数）的一段数据转换成
//                     一个字符串返回
// pos                 查找指定内容，找不到返回 -1

   HRaw(int InitSize = 4096, int StepSize = 1024);
   HRaw(const HString &Str,
      int InitSize = 4096, int StepSize = 1024);
   ~HRaw(void);
   HRaw(const HRaw &Obj);
   HRaw & operator=(const HRaw &Obj);
   int size(void) const;
   void resize(int Size);
   void clear(void);
   void push_back(const char *Data, int Len);
   void push_back(const HString &Str);
   char & operator[](int Index);
   const char & operator[](int Index) const;
   char * data(void);
   const char * data(void) const;
   HString sub_string(int Offset, int Len) const;
   int pos(const char *Buf, int Len) const;
   int pos(const HString &Buf) const;

private :

   int FSize;
   int FCapacity;
   int FInitSize;
   int FStepSize;
   vector<char> FArray;
};

class HStream
{
public :
   HStream()
   {
      FRecLen = -1;
   }
   virtual ~HStream();
   virtual int ReadLine(char *Line, int MaxLen,
      bool TabToSpace)
   {
      fprintf(stderr, "HStream::ReadLine!!!\n");
      return -1;
   }
   virtual void WriteLine(const char *Line)
   {
   }
   virtual int ReadRec(char *Buf, int MaxLen)
   {
      return -1;
   }
   virtual int WriteRec(const char *Rec, int Len)
   {
      return 0;
   }
   virtual int GetRecLen()
   {
      return FRecLen;
   }
   int ReadLine(char *Line, int MaxLen)
   {
      return ReadLine(Line, MaxLen, true);
   }
protected :

   int FRecLen;
};

class HFileStream : public HStream
{
public :
   HFileStream(FILE *File);
   virtual ~HFileStream();
   virtual int ReadLine(char *Line, int MaxLen,
      bool TabToSpace);
   virtual void WriteLine(const char *Line);
   virtual int ReadRec(char *Buf, int MaxLen);
   virtual int WriteRec(const char *Rec, int Len);
   FILE *GetFile()
   {
      return FFile;
   }
   int ReadLine(char *Line, int MaxLen)
   {
      return ReadLine(Line, MaxLen, true);
   }
private :
   FILE *FFile;
   char *FLine;
};

class HMemStream : public HStream
{
public :
   HMemStream(void *Buf = NULL, int Len = 0);
   virtual int ReadLine(char *Line, int MaxLen,
      bool TabToSpace);
   virtual void WriteLine(const char *Line);
   char *GetBuf(void);
   int GetLength(void);
   int ReadLine(char *Line, int MaxLen)
   {
      return ReadLine(Line, MaxLen, true);
   }
private :
   vector<char> FMem;
   int FPos;
};

class HVecStream : public HStream
{
public :
   explicit HVecStream(vector<HString> &AVec)
      : HStream(), StrVec(AVec), Idx(0)
   {
   }
   virtual int ReadLine(char *Line, int MaxLen,
      bool TabToSpace);
   virtual void WriteLine(const char *Line);
   int ReadLine(char *Line, int MaxLen)
   {
      return ReadLine(Line, MaxLen, true);
   }
private :
   vector<HString> &StrVec;
   int Idx;
};

};
#endif
